
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
export default class Cockpit3d {

    constructor(_element) {
        this._initScene(_element);
        this.shapes = [];
    }


    /**
     * 初始化场景
     */
    initScene() {
        this.scene = new THREE.Scene();
    }
    /**
     * 初始化相机
     */
    initCamera() {
        this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        // position and point the camera to the center of the scene
        this.camera.position.set(-30, 40, 30);
        this.camera.lookAt(this.scene.position);
    }

    /**
     * 初始化渲染器
     */
    initRenderer(_element) {

        // create a render and set the size
        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setClearColor(new THREE.Color(0x87CEEB));
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.antialias = true;

        this.renderer.alpha = true;

        this.renderer.precision = 'mediump'
        // add the output of the renderer to the html element
        this.container = document.getElementById(_element);
        this.container.appendChild(this.renderer.domElement);
    }

    initControls() {
        this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        // 设置控制器阻尼，让控制器更有真是效果，必须在动画循环里调用update（）
        //this.controls.enableDamping = true;
        this.controls.minPolarAngle = 0;
        this.controls.maxPolarAngle = 75 / 180 * Math.PI;
        this.controls.minDistance = 200;
        this.controls.maxDistance = 500; // 相机位置与观察目标点最大值
    }

    /**
     * 初始化灯光
     */
    initLight() {
        this.light = new THREE.SpotLight(0xffffff);
        this.light.position.set(-300, 600, -400);
        this.light.castShadow = true;
        this.scene.add(this.light);
        this.scene.add(new THREE.AmbientLight(0x404040));
    }

    update() {
        this.controls.update();

        this.upDownShap();
    }

    _initScene(_element) {

        this.initScene();
        this.initCamera();
        this.initRenderer(_element);
        this.initLight();
        this.initControls();

        let _that = this;
        function animate() {
            requestAnimationFrame(animate);
            _that.renderer.render(_that.scene, _that.camera);
            _that.update(_that);
        }
        animate();

        addEventListener('click', function (event) {
            _that.onMouseDblclick(event, _that)
        }, false);
        window.addEventListener('mousemove', function (event) {
            _that.onMouseMove(event, _that)
        }, false);


    }

    addGltfObject(_modal) {
        const loader = new GLTFLoader();
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath('/js/three/examples/jsm/libs/draco/');
        loader.setDRACOLoader(dracoLoader);
        let _that = this;
        return new Promise((resolve, reject) => {
            loader.load(
                _modal.path,
                function (gltf) {
                    //需要添加的部分
                    gltf.scene.traverse(function (child) {
                        if (child.isMesh) {
                            child.material.emissive = child.material.color;
                            child.material.emissiveMap = child.material.map;
                        }
                    });
                    gltf.scene.scale.set(1, 1, 1);
                    _that.scene.add(gltf.scene);
                    resolve();
                },
                // called while loading is progressing
                function (xhr) {
                    console.log((xhr.loaded / xhr.total * 100) + '% loaded');
                },
                // called when loading has errors
                function (error) {
                    console.log('An error happened', error);
                    reject(error);
                }
            );
        })

    }
    addJpgBackgroup(_modal) {
        const texture = new THREE.TextureLoader().load(_modal.path);
        texture.mapping = THREE.EquirectangularReflectionMapping;
        texture.magFilter = THREE.LinearFilter;//③
        texture.minFilter = THREE.LinearMipmapLinearFilter;//④
        texture.encoding = THREE.sRGBEncoding;
        //texture.repeat.set( 4, 4 );
        this.scene.background = texture;
        this.scene.environment = texture;
    }
    addHdrBackgroup(_modal) {
        const rgbeLoader = new RGBELoader();
        //资源较大，使用异步加载
        let _that = this;
        rgbeLoader.loadAsync(_modal.path).then((texture) => {
            texture.mapping = THREE.EquirectangularReflectionMapping;
            //将加载的材质texture设置给背景和环境
            _that.scene.background = texture;
            _that.scene.environment = texture;
        });
    }



    clearThree(obj) {
        while (obj.children.length > 0) {
            this.clearThree(obj.children[0])
            obj.remove(obj.children[0]);
        }
        if (obj.geometry) obj.geometry.dispose()

        if (obj.material) {
            //in case of map, bumpMap, normalMap, envMap ...
            Object.keys(obj.material).forEach(prop => {
                if (!obj.material[prop])
                    return
                if (typeof obj.material[prop].dispose === 'function')
                    obj.material[prop].dispose()
            })
            obj.material.dispose()
        }
    }

    resetScene() {
        this.clearThree(this.scene);
    }

    setSelect3DObject(_callback) {
        this.selectCallBack = _callback;
    }

    onMouseMove(event, _that) {
        let intersects = _that.getIntersects(event, _that);
        if (!intersects || intersects.length === 0) {
            return;
        }
        let _name = "";
        document.body.style.cursor = 'default';
        for (let _index = 0; _index < intersects.length; _index++) {
            _name = intersects[_index].object.name;
            if (_name.endsWith('_focus') || _name.endsWith('_text')) {
                document.body.style.cursor = 'pointer'; // 将鼠标状态设置为小手  
                break;
            }
        }
    }

    onMouseDblclick(event, _that) {
        //alert("a");
        //获取raycaster和所有模型相交的数组，其中的元素按照距离排序，越近的越靠前
        let intersects = _that.getIntersects(event, _that);
        // console.log(intersects[0].object);

        //获取选中最近的Mesh对象
        //instance坐标是对象，右边是类，判断对象是不是属于这个类的
        let _name = ''; //&& intersects[0].object.type === 'Mesh'
        if (intersects.length !== 0) {
            //intersects[0].object.material.color.set(0x00FF00);
            //console.log(intersects[0].object.material.color);
            for (let _index = 0; _index < intersects.length; _index++) {
                _name = intersects[_index].object.name;
                if (_name == 'X' || _name == 'Y' || _name == 'Z'
                    || _name == 'XY' || _name == 'XZ' || _name == 'YZ'
                    || _name == 'XYZ' || _name == 'E' || _name == 'XYZE'
                    || _name == 'START' || _name == 'END') {
                    continue
                }
                if (intersects[_index].object.type === 'Mesh') {
                    _that.selectObject = intersects[_index].object;
                    if (_that.selectCallBack) {
                        _that.selectCallBack(_that.selectObject);
                    }
                    break;
                }
            }

            //changeMaterial(selectObject)

        } else {
            console.log('未选中 Mesh!');
        }
    }

    getIntersects(event, _that) {

        if (event.target.tagName != 'CANVAS') {
            return [];
        }

        event.preventDefault();// 阻止默认的点击事件执行, https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault
        // console.log("event.clientX:" + event.clientX);
        // console.log("event.clientY:" + event.clientY);

        //声明 rayCaster 和 mouse 变量
        let rayCaster = new THREE.Raycaster();
        let mouse = new THREE.Vector2();

        //通过鼠标点击位置，计算出raycaster所需点的位置，以屏幕为中心点，范围-1到1
        mouse.x = ((event.clientX - _that.container.getBoundingClientRect().left) / _that.container.offsetWidth) * 2 - 1;
        mouse.y = -((event.clientY - _that.container.getBoundingClientRect().top) / _that.container.offsetHeight) * 2 + 1; //这里为什么是-号，没有就无法点中

        //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
        rayCaster.setFromCamera(mouse, _that.camera);

        //获取与射线相交的对象数组， 其中的元素按照距离排序，越近的越靠前。
        //+true，是对其后代进行查找，这个在这里必须加，因为模型是由很多部分组成的，后代非常多。
        let intersects = rayCaster.intersectObjects(_that.scene.children, true);

        //返回选中的对象
        return intersects;
    }

    getObjectByName(_objName) {
        return this.scene.getObjectByName(_objName);
    }

    addConicalShape(_objName) {
        let geometry = new THREE.ConeGeometry(8, 15, 20); // 第三个参数是分段数，可以根据需要调整  

        // 创建材质  
        let material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.7 }); // 绿色  

        // 创建锥形对象  
        let cone = new THREE.Mesh(geometry, material);
        cone.name = _objName;
        cone.rotation.x = Math.PI;
        this.scene.add(cone); // 将锥形对象添加到场景中  
    }

    addText(_objName, _text, _position) {
        let _that = this;
        const loader = new FontLoader();
        loader.load('/js/three/examples/fonts/helvetiker_regular.typeface.json', function (font) {
            const geometry = new TextGeometry(_text, {
                font: font,
                size: 6,
                height: 1,
                curveSegments: 8,
                bevelEnabled: true,
                bevelThickness: 1,
                bevelSize: 0.1,
                bevelSegments: 2
            });
           
            let material = new THREE.MeshBasicMaterial({ color: 0xc17e14, transparent: true, opacity: 0.8}); // 创建材质  
            let mesh = new THREE.Mesh(geometry, material); // 创建网格并添加到场景中  
            mesh.name = _objName;
            //mesh.scale.set(10, 10, 10)
            mesh.position.set(_position.x, _position.y, _position.z);
            mesh.rotateX(270/180 * Math.PI)
            _that.scene.add(mesh); // 将锥形对象添加到场景中 
        });
    }

    getObjectPosition(targetObject) {
        let targetCenter = new THREE.Vector3();
        // targetObject.updateMatrixWorld(true); // 确保目标物体的世界矩阵是最新的  
        // targetObject.getWorldPosition(targetCenter); // 将目标物体的世界位置存储到 targetCenter 中  
        // // 将源物体的位置设置为目标物体的中心位置  
        // console.log(targetCenter);
        let box = new THREE.Box3().setFromObject(targetObject);
        targetCenter.x = (box.max.x + box.min.x) / 2;
        targetCenter.y = box.min.y;
        targetCenter.z = (box.max.z + box.min.z) / 2;

        return { x: targetCenter.x, y: targetCenter.y, z: targetCenter.z };
    }

    getObjectHeight(targetObject) {
        let box = new THREE.Box3().setFromObject(targetObject);
        // 获取包围盒的高度  
        let height = box.max.y - box.min.y;
        return height;
    }

    addShap(_object) {

        this.shapes.push({
            object: _object,
            y: _object.position.y
        });
    }

    upDownShap() {
        if (!this.shapes || this.shapes.length < 1) {
            return;
        }
        // 设置移动的速度和幅度  
        let speed = 1.5; // 移动速度  
        let amplitude = 5; // 移动幅度  
        this.shapes.forEach(shape => {
            let newYPosition = shape.y + amplitude * Math.sin(speed * Date.now() / 1000);
            shape.object.position.y = newYPosition;

        })
    }

    lookAtObject(_object) {
        // 将相机移动到物体位置并面对物体  
        let _pos = this.getObjectPosition(_object);
        this.camera.position.set(_pos.x, _pos.y, _pos.z);
        this.camera.lookAt(_object.position);
    }
}